home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
shells
/
bashsrc.zoo
/
readline
/
history.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-29
|
35KB
|
1,479 lines
/* History.c -- standalone history library */
/* Copyright (C) 1989 Free Software Foundation, Inc.
This file contains the GNU History Library (the Library), a set of
routines for managing the text of previously typed lines.
The Library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
The Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
675 Mass Ave, Cambridge, MA 02139, USA. */
/* The goal is to make the implementation transparent, so that you
don't have to know what data types are used, just what functions
you can call. I think I have done that. */
/* Remove these declarations when we have a complete libgnu.a. */
#define STATIC_MALLOC
#ifndef STATIC_MALLOC
extern char *xmalloc (), *xrealloc ();
#else
static char *xmalloc (), *xrealloc ();
#endif
#include <stdio.h>
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
#if defined (sparc) && defined (sun)
#include <alloca.h>
#else
extern char *alloca ();
#endif
#endif
#include "history.h"
#ifndef savestring
#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
#endif
#ifndef whitespace
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
#endif
#ifndef digit
#define digit(c) ((c) >= '0' && (c) <= '9')
#endif
#ifndef member
#define member(c, s) ((c) ? index ((s), (c)) : 0)
#endif
/* **************************************************************** */
/* */
/* History functions */
/* */
/* **************************************************************** */
/* An array of HIST_ENTRY. This is where we store the history. */
static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
/* Non-zero means that we have enforced a limit on the amount of
history that we save. */
static int history_stifled = 0;
/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
entries to remember. */
static int max_input_history;
/* The current location of the interactive history pointer. Just makes
life easier for outside callers. */
static int history_offset = 0;
/* The number of strings currently stored in the input_history list. */
static int history_length = 0;
/* The current number of slots allocated to the input_history. */
static int history_size = 0;
/* The number of slots to increase the_history by. */
#define DEFAULT_HISTORY_GROW_SIZE 50
/* The character that represents the start of a history expansion
request. This is usually `!'. */
char history_expansion_char = '!';
/* The character that invokes word substitution if found at the start of
a line. This is usually `^'. */
char history_subst_char = '^';
/* During tokenization, if this character is seen as the first character
of a word, then it, and all subsequent characters upto a newline are
ignored. For a Bourne shell, this should be '#'. Bash special cases
the interactive comment character to not be a comment delimiter. */
char history_comment_char = '\0';
/* The list of characters which inhibit the expansion of text if found
immediately following history_expansion_char. */
char *history_no_expand_chars = " \t\n\r=";
/* The logical `base' of the history array. It defaults to 1. */
int history_base = 1;
/* Begin a session in which the history functions might be used. This
initializes interactive variables. */
void
using_history ()
{
history_offset = history_length;
}
/* Place STRING at the end of the history list. The data field
is set to NULL. */
void
add_history (string)
char *string;
{
HIST_ENTRY *temp;
if (history_stifled && (history_length == max_input_history)) {
register int i;
/* If the history is stifled, and history_length is zero,
and it equals max_input_history, we don't save items. */
if (!history_length)
return;
/* If there is something in the slot, then remove it. */
if (the_history[0]) {
free (the_history[0]->line);
free (the_history[0]);
}
for (i = 0; i < history_length; i++)
the_history[i] = the_history[i + 1];
history_base++;
} else {
if (!history_size) {
the_history =
(HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
* sizeof (HIST_ENTRY *));
history_length = 1;
} else {
if (history_length == (history_size - 1)) {
the_history =
(HIST_ENTRY **)xrealloc (the_history,
((history_size += DEFAULT_HISTORY_GROW_SIZE)
* sizeof (HIST_ENTRY *)));
}
history_length++;
}
}
temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
temp->line = savestring (string);
temp->data = (char *)NULL;
the_history[history_length] = (HIST_ENTRY *)NULL;
the_history[history_length - 1] = temp;
}
/* Make the history entry at WHICH have LINE and DATA. This returns
the old entry so you can dispose of the data. In the case of an
invalid WHICH, a NULL pointer is returned. */
HIST_ENTRY *
replace_history_entry (which, line, data)
int which;
char *line;
char *data;
{
HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
HIST_ENTRY *old_value;
if (which >= history_length)
return ((HIST_ENTRY *)NULL);
old_value = the_history[which];
temp->line = savestring (line);
temp->data = data;
the_history[which] = temp;
return (old_value);
}
/* Returns the magic number which says what history element we are
looking at now. In this implementation, it returns history_offset. */
int
where_history ()
{
return (history_offset);
}
/* Search the history for STRING, starting at history_offset.
If DIRECTION < 0, then the search is through previous entries,
else through subsequent. If the string is found, then
current_history () is the history entry, and the value of this function
is the offset in the line of that history entry that the string was
found in. Otherwise, nothing is changed, and a -1 is returned. */
int
history_search (string, direction)
char *string;
int direction;
{
register int i = history_offset;
register int reverse = (direction < 0);
register char *line;
register int index;
int string_len = strlen (string);
/* Take care of trivial cases first. */
if (!history_length || (i == history_length) && !reverse)
return (-1);
if (reverse && (i == history_length))
i--;
while (1)
{
/* Search each line in the history list for STRING. */
/* At limit for direction? */
if ((reverse && i < 0) ||
(!reverse && i == history_length))
return (-1);
line = the_history[i]->line;
index = strlen (line);
/* If STRING is longer than line, no match. */
if (string_len > index)
goto next_line;
/* Do the actual search. */
if (reverse)
{
index -= string_len;
while (index >= 0)
{
if (strncmp (string, line + index, string_len) == 0)
{
history_offset = i;
return (index);
}
index--;
}
}
else
{
register int limit = (string_len - index) + 1;
index = 0;
while (index < limit)
{
if (strncmp (string, line + index, string_len) == 0)
{
history_offset = i;
return (index);
}
index++;
}
}
next_line:
if (reverse)
i--;
else
i++;
}
}
/* Remove history element WHICH from the history. The removed
element is returned to you so you can free the line, data,
and containing structure. */
HIST_ENTRY *
remove_history (which)
int which;
{
HIST_ENTRY *return_value;
if (which >= history_length || !history_length)
return_value = (HIST_ENTRY *)NULL;
else
{
register int i;
return_value = the_history[which];